package com.example.cadmin.utils.PDF;

import java.io.*;

import com.lowagie.text.Document;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import lombok.Cleanup;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @Title: 需要引入<code>com.lowagie.itext  2.1.7 <code/> 依赖
 * @description: 多个pdf 文件合并成一个pdf文件
 **/
public class mergePDF {

    /**
     * 多个pdf文件合并
     * @param files 待合并的文件数组
     * @param newfile 新的文件全路径信息(带文件名)
     * @return
     */
    public static boolean mergePdfFiles(String[] files, String newfile) {
        boolean retValue = false;
        Document document = null;
        PdfCopy copy = null;
        PdfReader reader = null;
        try {
            document = new Document(new PdfReader(files[0]).getPageSize(1));
            copy = new PdfCopy(document, new FileOutputStream(newfile));
            document.open();
            for (int i = 0; i < files.length; i++) {
                reader = new PdfReader(files[i]);
                int n = reader.getNumberOfPages();
                for (int j = 1; j <= n; j++) {
                    document.newPage();
                    PdfImportedPage page = copy.getImportedPage(reader, j);
                    copy.addPage(page);
                }
                reader.close();
            }
            retValue = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (copy != null) {
                copy.close();
            }
            if (document != null) {
                document.close();
            }
        }
        return retValue;
    }

    /**
     * 将文件集合信息 ，合并到 <code>newfile<code/>文件名的新pdf文件中
     * @param files  待合并的pdf文件
     * @param newfile 合并后新生成的pdf文件(如果不是全路径，则会生成在项目同级目录下)
     * @return
     */
    public static boolean mergePdfFiles(List<String> files, String newfile) {
        if(CollectionUtils.isEmpty(files)){
            return Boolean.FALSE;
        }
        boolean retValue = false;
        Document document = null;
        PdfCopy copy = null;
        PdfReader reader = null;
        try {
            // 以第一个pdf 作为基准
            PdfReader pdfReader = new PdfReader(files.get(0));
            Rectangle rectangle = pdfReader.getPageSize(1);
            document = new Document(rectangle);
            // 以第一个pdf 构建新的pdf文件输出流
            copy = new PdfCopy(document, new FileOutputStream(newfile));
            document.open();
            for (int i = 0; i < files.size(); i++) {
                // 读取pdf文件
                reader = new PdfReader(files.get(i));
                int n = reader.getNumberOfPages();
                for (int j = 1; j <= n; j++) {
                    document.newPage(); // 创建新的pdf页数
                    PdfImportedPage page = copy.getImportedPage(reader, j);
                    copy.addPage(page);
                }
                reader.close();
            }
            retValue = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (copy != null) {
                copy.close();
            }
            if (document != null) {
                document.close();
            }
        }
        return retValue;
    }

    /**
     * 将pdf的base64 编码，转换成对应的pdf文件暂存，并返回文件名称集合
     * @param base64Lists
     * @return
     * @throws Exception
     */
    public static List<String> base64ToFile(List<String> base64Lists) throws Exception {
        if(CollectionUtils.isEmpty(base64Lists)){
            return null;
        }
        List<String> returnStrLists = new ArrayList<>();
        BASE64Decoder decoder = new BASE64Decoder();
        for (String base64Str : base64Lists) {
            byte[] fileBytes = decoder.decodeBuffer(base64Str);
            @Cleanup ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(fileBytes);
            // 此处代码会导致生成的文件很大
            // @Cleanup ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(fileBytes.length);

            // 生成临时文件  为了保证文件的唯一性，必须名称不同
            String fileName = "report_"+UUID.randomUUID().toString()+".pdf";
            returnStrLists.add(fileName); // 返回调用方文件名集合
            // 暂存文件
            @Cleanup OutputStream outputStream = new FileOutputStream(fileName);
//            int c = 0;
//            while (c < byteArrayInputStream.read()){
//                byteArrayOutputStream.write(fileBytes);
//                byteArrayOutputStream.writeTo(outputStream);
//                byteArrayOutputStream.flush();
//            }
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = byteArrayInputStream.read(bytes)) > 0){
                outputStream.write(bytes,0,len);
            }
        }
        return returnStrLists;
    }

    /**
     * 根据获取到的pdf base64 文件流集合，生成临时文件，并重新读取临时文件，进行pdf的合并。
     * @param base64Pdfs 各个合同类型数据pdf文件base64数据流
     * @return 新的已合并的pdf文件流的base64 数据值
     * @throws Exception
     */
    public static String getNewMergePdfBase64(List<String> base64Pdfs) throws Exception {
        String newPdfName = null;
        List<String> fileNameLists = null;
        try {
            fileNameLists = base64ToFile(base64Pdfs);
            newPdfName = "report_"+UUID.randomUUID().toString()+".pdf";
            mergePdfFiles(fileNameLists, newPdfName);
            // 以新的文件名  读取成文件流  并转换base64 返回
            @Cleanup FileInputStream fileInputStream = new FileInputStream(newPdfName);
            return base64ForPdf(fileInputStream);
        }finally {
            // 如果临时文件存在，则删除临时文件
            if(StringUtils.isNotBlank(newPdfName)){
                File file = new File(newPdfName);
                if (file != null && file.isFile() && file.exists()) {
                    file.delete();
                }
            }
            if(!CollectionUtils.isEmpty(fileNameLists)){
                for (String fileName : fileNameLists) {
                    File file = new File(fileName);
                    if (file != null && file.isFile() && file.exists()) {
                        file.delete();
                    }
                }
            }
        }
    }
    /**
     *将文件输入流，转换为 base64 返回给请求端
     **/
    public static String base64ForPdf(InputStream fin) throws Exception {
        BASE64Encoder encoder = new BASE64Encoder();

        BufferedInputStream bin = new BufferedInputStream(fin);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedOutputStream bout = new BufferedOutputStream(baos);
        byte[] buffer = new byte[1024];

        for (int len = bin.read(buffer); len != -1; len = bin.read(buffer)) {
            bout.write(buffer, 0, len);
        }

        bout.flush();
        byte[] bytes = baos.toByteArray();
        String var11 = encoder.encodeBuffer(bytes).trim();
        return var11;
    }

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>(){{
            add("C:\\Users\\Administrator\\Desktop\\1\\20240422181022492.pdf");
            add("C:\\Users\\Administrator\\Desktop\\1\\123.pdf");
        }};
        boolean result = mergePdfFiles(list,"C:\\Users\\Administrator\\Desktop\\test.pdf");
        System.out.println(result);
    }
}
